home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 May: Tool Chest / Dev.CD May 97 TC.toast / Sample Code / Snippets / Toolbox / Modal TextEdit / main.c next >
Encoding:
C/C++ Source or Header  |  1992-07-15  |  11.0 KB  |  488 lines  |  [TEXT/KAHL]

  1. /*
  2.     Modal Dialog TextEdit useritem snippet
  3.     Steve Falkenburg-- MacDTS
  4.     
  5.     This snippet shows the steps necessary to implement a scrolling, editable text field
  6.     in a dialog.  You may want to do this if you will be requiring the user to enter more than
  7.     255 characters (the limit for editText items), if you want a different font for several
  8.     different editText items, or it you want to add scrolling support to an editible text item.
  9. */
  10.  
  11.  
  12. // constants
  13.  
  14. #define    kMyDialog        128
  15. #define    kInFront        (WindowPtr)-1L
  16. #define    kEditTextItem    2
  17. #define    kScrollerItem    3
  18. #define    kMargin            4
  19. #define    kPageLines        16
  20. #define    kScrollToTop    0
  21. #define    kScrollToBottom    1
  22. #define    kMaxLines        128
  23. #define    kCheckOneItem    5
  24. #define    kCheckTwoItem    6
  25.  
  26. // prototypes
  27.  
  28. void main(void);
  29. void InitStuff(void);
  30. void DoDialog(void);
  31. void SetupDialog(DialogPtr theDialog);
  32. void PrepareFreeDialog(DialogPtr theDialog);
  33.  
  34. pascal void EditTextDrawProc(DialogPtr theDialog,short theItem);
  35. pascal Boolean MyDialogFilter(DialogPtr theDialog,EventRecord *ev,short *itemHit);
  36. void HandleKeyPress(DialogPtr theDialog,char theChar);
  37. void HandleIdle(DialogPtr theDialog);
  38. void HandleActivate(DialogPtr theDialog);
  39. Boolean HandleMouse(DialogPtr theDialog,Point pt,short modifiers);
  40.  
  41. void HandleScroller(DialogPtr theDialog,Point pt);
  42. pascal void ScrollBarAction(ControlHandle theControl,short part);
  43. void ScrollText(DialogPtr theDialog,short lines);
  44. void ReAlignTextToScrollbar(DialogPtr theDialog);
  45. void ReAlignScrollbarToText(DialogPtr theDialog);
  46.  
  47. pascal Boolean MyTEClickProc(void);
  48.  
  49. ControlHandle GetScrollBar(DialogPtr theDialog);
  50. TEHandle GetTEHandle(DialogPtr theDialog);
  51.  
  52.  
  53. /* main entry point */
  54.  
  55. void main(void)
  56. {
  57.     InitStuff();
  58.     DoDialog();
  59.     ExitToShell();
  60. }
  61.  
  62.  
  63. /* initialize the Mac managers */
  64.  
  65. void InitStuff(void)
  66. {
  67.     InitGraf(&qd.thePort);
  68.     InitFonts();
  69.     InitWindows();
  70.     InitMenus();
  71.     TEInit();
  72.     InitDialogs(nil);
  73.     InitCursor();
  74.     FlushEvents(everyEvent,0);
  75. }
  76.  
  77.  
  78. /*    display dialog, and handle pretty standard ModalDialog loop.  The modal dialog loop doesn't
  79.     handle item hits to the scroll bar or text items.  These are handled through the filter
  80.     procedure
  81. */
  82.  
  83. void DoDialog(void)
  84. {
  85.     DialogPtr theDialog;
  86.     short item;
  87.     ControlHandle checkBoxControl;
  88.     short iType;
  89.     Rect iRect;
  90.     
  91.     theDialog = GetNewDialog(kMyDialog,nil,kInFront);
  92.     SetupDialog(theDialog);
  93.         
  94.     do {
  95.         ModalDialog(MyDialogFilter,&item);
  96.         switch (item) {
  97.             case kCheckOneItem:    // check boxes
  98.             case kCheckTwoItem:
  99.                 GetDItem(theDialog,item,&iType,&checkBoxControl,&iRect);
  100.                 SetCtlValue(checkBoxControl,!GetCtlValue(checkBoxControl));
  101.                 break;
  102.         }    
  103.     } while (item!=ok);
  104.     
  105.     PrepareFreeDialog(theDialog);
  106.     DisposeDialog(theDialog);
  107. }
  108.  
  109.  
  110. /*    Creates the necessary data structures necessary to use the textedit item in our dialog.  A
  111.     handle to the TextEdit record is stored in the Dialog's window refCon field.
  112. */
  113.  
  114. void SetupDialog(DialogPtr theDialog)
  115. {
  116.     short iType;
  117.     Handle iHndl;
  118.     Rect iRect;
  119.     ControlHandle theControl;
  120.     short fontNum;
  121.     TEHandle theTE;
  122.     
  123.     SetPort(theDialog);
  124.     
  125.     GetDItem(theDialog,kScrollerItem,&iType,&theControl,&iRect);    // set up the scroll bar
  126.     SetCtlMin(theControl,0);                                        // (it's stored in a CNTL)
  127.     SetCtlMax(theControl,kMaxLines);
  128.  
  129.     GetDItem(theDialog,kEditTextItem,&iType,&iHndl,&iRect);
  130.     SetDItem(theDialog,kEditTextItem,iType,EditTextDrawProc,&iRect);
  131.     
  132.     InsetRect(&iRect,kMargin,kMargin);
  133.     
  134.     GetFNum("\pgeneva",&fontNum);
  135.     TextFont(fontNum);
  136.     theTE = TENew(&iRect,&iRect);            // create our textedit item
  137.     GetFNum("\pchicago",&fontNum);
  138.     TextFont(fontNum);
  139.  
  140.     SetClikLoop(MyTEClickProc,theTE);        // callback for drag-scrolling
  141.     TEAutoView(true,theTE);                    // turn auto-scroll on for text entry
  142.     
  143.     SetWRefCon(theDialog,(long)theTE);
  144. }
  145.  
  146.  
  147.  
  148. /*    free the memory taken by the textedit record before closing the dialog
  149. */
  150.  
  151. void PrepareFreeDialog(DialogPtr theDialog)
  152. {
  153.     TEHandle theTE;
  154.     
  155.     theTE = GetTEHandle(theDialog);
  156.     TEDispose(theTE);
  157. }
  158.  
  159.  
  160. /*    dialog user item draw procedure for text box.  It just calls FrameRect
  161. */
  162.  
  163. pascal void EditTextDrawProc(DialogPtr theDialog,short theItem)
  164. {
  165.     short iType;
  166.     Handle iHndl;
  167.     Rect iRect;
  168.     GrafPtr savePort;
  169.     
  170.     GetPort(&savePort);
  171.     SetPort(theDialog);
  172.     
  173.     GetDItem(theDialog,theItem,&iType,&iHndl,&iRect);
  174.     FrameRect(&iRect);
  175.     
  176.     SetPort(savePort);
  177. }
  178.  
  179.  
  180. /*    this is the main dispatcher for events to be passed off to the scroll bar or textedit box.
  181.     looks sort of like a WaitNextEvent event handler.
  182. */
  183.  
  184. pascal Boolean MyDialogFilter(DialogPtr theDialog,EventRecord *ev,short *itemHit)
  185. {
  186.     char theChar;
  187.     
  188.     switch (ev->what) {
  189.         case keyDown:
  190.         case autoKey:
  191.             theChar = (ev->message & charCodeMask);
  192.             HandleKeyPress(theDialog,theChar);
  193.             return true;
  194.         case nullEvent:
  195.             HandleIdle(theDialog);
  196.             return false;
  197.         case activateEvt:
  198.             HandleActivate(theDialog);
  199.             return false;
  200.         case mouseDown:
  201.             return HandleMouse(theDialog,ev->where,ev->modifiers);
  202.         default:
  203.             return false;
  204.     }
  205. }
  206.  
  207.  
  208. /*    dialog filter event handler for keypresses.  All keypresses are passed to the textedit box
  209. */
  210.  
  211. void HandleKeyPress(DialogPtr theDialog,char theChar)
  212. {
  213.     TEHandle theTE;
  214.  
  215.     theTE = GetTEHandle(theDialog);
  216.     TEKey(theChar,theTE);
  217.     ReAlignScrollbarToText(theDialog);
  218. }
  219.  
  220.  
  221. /*    handler for null events.  used in our case to blink the insertion point
  222. */
  223.  
  224. void HandleIdle(DialogPtr theDialog)
  225. {
  226.     TEHandle theTE;
  227.  
  228.     theTE = GetTEHandle(theDialog);
  229.     TEIdle(theTE);
  230. }
  231.  
  232.  
  233. /*    activate event handler.  we take this opportunity to call TEActivate to activate the textedit
  234.     box
  235. */
  236.  
  237. void HandleActivate(DialogPtr theDialog)
  238. {
  239.     TEHandle theTE;
  240.  
  241.     theTE = GetTEHandle(theDialog);
  242.     TEActivate(theTE);
  243. }
  244.  
  245.  
  246. /*    mouse-down hander.  here, we see if the mousedown was in the scrollbar or in the textedit
  247.     record.  if in the textedit item, we call teclick.  If in the scrollbar, we call handlescroller
  248.     to do further processing
  249. */
  250.  
  251. Boolean HandleMouse(DialogPtr theDialog,Point pt,short modifiers)
  252. {
  253.     short iType;
  254.     Handle iHndl;
  255.     Rect textRect,scrollerRect;
  256.     TEHandle theTE;
  257.     GrafPtr savePort;
  258.     Boolean shiftDown,result;
  259.     ControlHandle theControl;
  260.     short part;
  261.     
  262.     GetPort(&savePort);
  263.     SetPort(theDialog);
  264.     
  265.     shiftDown = modifiers & shiftKey;
  266.     GlobalToLocal(&pt);
  267.     
  268.     GetDItem(theDialog,kEditTextItem,&iType,&iHndl,&textRect);
  269.     GetDItem(theDialog,kScrollerItem,&iType,&iHndl,&scrollerRect);
  270.     
  271.     if (PtInRect(pt,&textRect)) {
  272.         theTE = GetTEHandle(theDialog);
  273.         TEClick(pt,shiftDown,theTE);
  274.         result = true;
  275.     }
  276.     else if (PtInRect(pt,&scrollerRect)) {
  277.         HandleScroller(theDialog,pt);
  278.         result = true;
  279.     }
  280.     else
  281.         result = false;
  282.         
  283.     SetPort(savePort);
  284.     
  285.     return result;
  286. }
  287.  
  288.  
  289. /*    here, we see which part of the scrollbar was clicked in by calling findcontrol.  trackcontrol
  290.     is then called with the appropriate action proc if in one of the buttons or page areas.  if
  291.     in the thumb, the text is simply re-aligned to the new scrollbar position
  292. */
  293.  
  294. void HandleScroller(DialogPtr theDialog,Point pt)
  295. {
  296.     short part;
  297.     ControlHandle theControl;
  298.     
  299.     part = FindControl(pt,theDialog,&theControl);
  300.     switch (part) {
  301.         case inUpButton:
  302.         case inDownButton:
  303.         case inPageUp:
  304.         case inPageDown:
  305.             TrackControl(theControl,pt,ScrollBarAction);
  306.             break;
  307.         case inThumb:
  308.             TrackControl(theControl,pt,nil);
  309.             ReAlignTextToScrollbar(theDialog);
  310.             break;
  311.     }
  312. }
  313.  
  314.  
  315. /*    trackcontrol callback used to determine which direction to scroll the text, and by how much.
  316.     once this is known, the text is scrolled, and the scrollbar adjusted.
  317. */
  318.  
  319. pascal void ScrollBarAction(ControlHandle theControl,short part)
  320. {
  321.     DialogPtr theDialog;
  322.     short lines;
  323.     short ctlValue,ctlMax,ctlMin;
  324.     
  325.     ctlMax = GetCtlMax(theControl);
  326.     ctlMin = GetCtlMin(theControl);
  327.     ctlValue = GetCtlValue(theControl);
  328.     
  329.     theDialog = (*theControl)->contrlOwner;
  330.     
  331.     switch (part) {
  332.         case inUpButton:
  333.             lines = -1;
  334.             break;
  335.         case inDownButton:
  336.             lines = 1;
  337.             break;
  338.         case inPageUp:
  339.             lines = -kPageLines;
  340.             break;
  341.         case inPageDown:
  342.             lines = kPageLines;
  343.             break;
  344.         default:
  345.             return;
  346.     }
  347.  
  348.     if ((ctlValue+lines)>ctlMax)
  349.         lines = ctlMax-ctlValue;
  350.     if ((ctlValue+lines)<ctlMin)
  351.         lines = ctlMin-ctlValue;
  352.         
  353.     if (lines!=0) {
  354.         ScrollText(theDialog,lines);
  355.         SetCtlValue(theControl,ctlValue+lines);
  356.     }
  357. }
  358.  
  359.  
  360. /*    sets the text top line to be the same as the current scrollbar position.  this is called after
  361.     a thumb movement in the scrollbar.
  362. */
  363.  
  364. void ReAlignTextToScrollbar(DialogPtr theDialog)
  365. {
  366.     TEHandle theTE;
  367.     ControlHandle scrollBar;
  368.     short controlScrollPosition,textScrollPosition,scrollDelta,scrollPix;
  369.     
  370.     theTE = GetTEHandle(theDialog);
  371.     scrollBar = GetScrollBar(theDialog);
  372.     
  373.     controlScrollPosition = GetCtlValue(scrollBar);
  374.     textScrollPosition = ((**theTE).viewRect.top - (**theTE).destRect.top) / (**theTE).lineHeight;
  375.     scrollDelta = textScrollPosition - controlScrollPosition;
  376.     scrollPix = scrollDelta * (*theTE)->lineHeight;
  377.     TEScroll(0,scrollPix,theTE);
  378. }
  379.  
  380.  
  381. /*    sets the scrollbar thumb to the current text position.  this is called after autoscrolling,
  382.     which may occur after a call to TEKey, or during a drag-scroll
  383. */
  384.  
  385. void ReAlignScrollbarToText(DialogPtr theDialog)
  386. {
  387.     TEHandle theTE;
  388.     ControlHandle scrollBar;
  389.     short textScrollPosition;
  390.         
  391.     theTE = GetTEHandle(theDialog);
  392.     scrollBar = GetScrollBar(theDialog);
  393.     
  394.     textScrollPosition = ((**theTE).viewRect.top - (**theTE).destRect.top) / (**theTE).lineHeight;
  395.     SetCtlValue(scrollBar,textScrollPosition);
  396. }
  397.  
  398.  
  399. /*    scrolls the text by the delta passed in to the function.  called in response to clicking the
  400.     arrows or page areas of the scrollbar to move the text
  401. */
  402.  
  403. void ScrollText(DialogPtr theDialog,short lines)
  404. {
  405.     TEHandle theTE;
  406.     short scrollPix;
  407.     short textScrollPosition;
  408.     
  409.     theTE = GetTEHandle(theDialog);
  410.  
  411.     textScrollPosition = ((**theTE).viewRect.top - (**theTE).destRect.top) / (**theTE).lineHeight;
  412.     if ((textScrollPosition+lines)<0)
  413.         lines = -textScrollPosition;
  414.     if ((textScrollPosition+lines)>kMaxLines)
  415.         lines = kMaxLines-textScrollPosition;
  416.                 
  417.     scrollPix = lines * (*theTE)->lineHeight;
  418.     
  419.     TEScroll(0,-scrollPix,theTE);
  420. }
  421.  
  422.  
  423. /*    text drag callback procedure.  this routine handles drag scrolling by checking to see if we
  424.     are in the area where drag-scrolling is necessary, and calling scrolltext followed by a
  425.     scrollbar realignment
  426. */
  427.  
  428. pascal Boolean MyTEClickProc(void)
  429. {
  430.     Point pt;
  431.     DialogPtr theDialog;
  432.     ControlHandle theControl;
  433.     TEHandle theTE;
  434.     Rect textRect;
  435.     short scrollLines;
  436.     GrafPtr savePort;
  437.     RgnHandle saveClip;
  438.         
  439.     GetMouse(&pt);
  440.     theDialog = (DialogPtr)FrontWindow();
  441.     theTE = GetTEHandle(theDialog);
  442.     
  443.     GetPort(&savePort);
  444.     SetPort(theDialog);
  445.  
  446.     saveClip = NewRgn();
  447.     GetClip(saveClip);
  448.     ClipRect(&theDialog->portRect);
  449.  
  450.     scrollLines = 0;
  451.     textRect = (**theTE).viewRect;
  452.     if (pt.v < textRect.top)
  453.         scrollLines = -1;
  454.     else if (pt.v > textRect.bottom)
  455.         scrollLines = 1;
  456.     
  457.     if (scrollLines) {
  458.         ScrollText(theDialog,scrollLines);
  459.         ReAlignScrollbarToText(theDialog);
  460.     }
  461.     
  462.     SetClip(saveClip);
  463.     DisposHandle(saveClip);
  464.     SetPort(savePort);
  465.     return true;
  466. }
  467.  
  468.  
  469. /*    utility procedure to return a handle to the scrollbar control
  470. */
  471.  
  472. ControlHandle GetScrollBar(DialogPtr theDialog)
  473. {
  474.     ControlHandle theScroller;
  475.     short iType;
  476.     Rect iRect;
  477.     
  478.     GetDItem(theDialog,kScrollerItem,&iType,&theScroller,&iRect);
  479.     return theScroller;
  480. }
  481.  
  482.  
  483. /*    utility procedure to return the textedit record for the given dialog */
  484.  
  485. TEHandle GetTEHandle(DialogPtr theDialog)
  486. {
  487.     return( (TEHandle)GetWRefCon((WindowPtr)theDialog) );
  488. }